package com.recharge.service.httpInterFace;

import com.alibaba.fastjson.JSONObject;
import com.recharge.common.result.ResultDO;
import com.recharge.common.result.ResultSupport;
import com.recharge.common.util.Constant;
import com.recharge.common.util.DESUtil;
import com.recharge.common.util.TemplateUtils;
import com.recharge.common.util.http.HttpClientUtil;
import com.recharge.domain.query.OrderStatusQueryDO;
import com.recharge.domain.vo.GoodsChannelDO;
import com.recharge.domain.vo.ProviderApiDO;
import com.recharge.domain.vo.ProviderCallbackDO;
import com.recharge.service.ProviderApiService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;

/**
 * <h1>上游请求(月兔)</h1>
 */
@Service
public class YueTuHTTPImpl implements ProviderHTTPService {

    private Logger logger = LoggerFactory.getLogger(this.getClass().getName());

    @Autowired
    ProviderApiService providerApiService;

    @Override
    public ResultDO commitOrder(GoodsChannelDO domain) {
        // 判断订单流水是否为空
        if (!verifyCommitParam(domain)) {
            return returnFail(false
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_FAIL
                    , String.format("订单提交 >> 请求参数缺失 %s", domain.toString())
                    , "请求参数缺失"
                    , null);
        }

        //请求金额
        Long amount = domain.getAmount();
        //商品编号
        String goodsNo = domain.getProviderGoodsNo();
        //平台流水号
        String serialNumber = domain.getProviderSerialNumber();
        //充值号码
        String rechargeNumber = domain.getRechargeNumber();
        //供应商上游请求账号
        String userId = domain.getUserId();
        //供应商密钥
        String privateKey = domain.getPrivateKey();
        //供应商ID
        String providerId = domain.getProviderId();

        // 添加存根
        ProviderCallbackDO callbackDO = new ProviderCallbackDO();
        callbackDO.setSerialNumber(serialNumber);
        callbackDO.setProviderId(providerId);
        callbackDO.setOrderNo(domain.getOrderNo());
        callbackDO.setStatus(Constant.CALL_BACK_PROCESS);
        ResultDO result = providerApiService.addCallback(callbackDO);
        if (!result.isSuccess()) {
            return returnFail(false
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_FAIL
                    , String.format("订单提交 >> 订单%s添加回调数据失败", serialNumber)
                    , "添加回调存根信息失败"
                    , null);
        }

        String json = "{" +
                "    \"goodsNo\":\"" + goodsNo + "\"," +
                "    \"goodsQuantity\":1," +
                "    \"goodsType\":1,\n" +
                "    \"merchantNo\":\"" + userId + "\"," +
                "    \"price\":" + amount + "," +
                "    \"rechargeNumber\":\"" + rechargeNumber + "\"," +
                "    \"serialNumber\":\"" + serialNumber + "\"," +
                "    \"timestamp\":" + System.currentTimeMillis() + "," +
                "    \"version\":\"1\"" +
                "}";
        String sign = DESUtil.encrypt(privateKey, json);

        String sendParam = "{" +
                "\"privateKey\":\"" + privateKey + "\"," +
                "\"encryptionData\":\"" + sign + "\"" +
                "}";

        // 发送请求
        logger.warn(String.format("发送POST请求(订单号%s): %s?%s", serialNumber, domain.getRequestUrl(), sendParam));
        String sendResult = HttpClientUtil.doPostJson(domain.getRequestUrl(), sendParam);
        switch (sendResult) {
            case "500":
                return returnFail(false
                        , Constant.BUSINESS_RECHARGE_RETURN_STATUS_FAIL
                        , String.format("订单提交 >> 订单 %s -> 订单提交供货商HTTP请求失败", serialNumber)
                        , "HTTP请求失败"
                        , sendResult);
            case "504":
                return returnFail(false
                        , Constant.BUSINESS_RECHARGE_RETURN_STATUS_OUT_TIME
                        , String.format("订单提交 >> 订单 %s -> 订单提交供货商HTTP请求超时", serialNumber)
                        , "HTTP请求超时"
                        , sendResult);
            case "":
                return returnFail(false
                        , Constant.BUSINESS_RECHARGE_RETURN_STATUS_OUT_TIME
                        , String.format("订单提交 >> 订单 %s -> 订单提交供货商HTTP请求没有返回信息", serialNumber)
                        , "订单提交没有返回信息"
                        , sendResult);
        }
        logger.warn(String.format("订单提交 >> 请求返回信息: 订单号%s -> %s", serialNumber, sendResult));

        // 解析请求返回结果转换为json对象
        JSONObject resultJson = new JSONObject();
        try {
            resultJson = JSONObject.parseObject(sendResult);
        } catch (Exception e) {
            logger.debug(String.format("请求返回结果解析json失败: %s", sendResult));
        }
        if (resultJson.size() == 0) {
            return returnFail(false
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_OUT_TIME
                    , String.format("订单提交 >> 订单号 %s -> 提交订单没有返回信息", serialNumber)
                    , "没有返回信息"
                    , sendResult);
        }

        String code = null;
        String desc = "";
        try {
            code = resultJson.get("status").toString();
            desc = resultJson.get("msg").toString();
        } catch (Exception e) {
            logger.debug(String.format("订单提交 >> 获取返回信息失败: 订单号%s -> %s", serialNumber, sendResult));
        }
        if (code == null) {
            return returnFail(false
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_OUT_TIME
                    , String.format("订单提交 >> 订单号 %s -> 没有获取到返回状态码", serialNumber)
                    , "没有获取到返回状态码"
                    , sendResult);
        }

        if ("200".equals(code)) { //成功
            logger.debug(String.format("订单提交 >> 订单号 %s -> 订单提交成功|%s", serialNumber, desc));
            result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.BUSINESS_RECHARGE_RETURN_STATUS_SUCCESS);
            return result;
        } else {//失败
            return returnFail(true
                    , Constant.BUSINESS_RECHARGE_RETURN_STATUS_FAIL
                    , String.format("订单提交 >> 订单号 %s -> 订单失败|%s", serialNumber, desc)
                    , String.format("%s %s", desc, code)
                    , sendResult);
        }
    }

    @Override
    public ResultDO backOrder(ProviderApiDO domain, String paramStr, String bodyStr) {
        ResultDO result = new ResultSupport();
        JSONObject jsonObject = null;
        try {
            jsonObject = JSONObject.parseObject(bodyStr);
            logger.debug("订单异步回调 >> " + domain.getProviderNo() + "解析后数据: " + jsonObject.toJSONString());
        } catch (Exception e) {
            logger.debug("订单异步回调 >> " + domain.getProviderNo() + "解析失败:" + paramStr);
        }
        if (jsonObject == null) {
            logger.debug("订单异步回调 >> 收到异步回调,但是没有回调信息");
            result.setModel(ResultDO.FIRST_MODEL_KEY, "fail");
            return result;
        }

        //状态码
        String status = "";
        //充值凭证
        String voutcher = "";
        //上游流水号
        String orderNo = "";
        //平台流水号
        String serialNum = "";
        try {
            status = jsonObject.getString("code");
            voutcher = jsonObject.getString("voucherNo");
            orderNo = jsonObject.getString("orderNo");
            serialNum = jsonObject.getString("serialNumber");
        } catch (Exception e) {
            logger.debug(e.getMessage());
        }

        String[] array = {"500", "8001", "8002", "8003", "8004", "8005", "8006", "8007", "8015", "8016", "8017", "8018", "8019", "8020", "8021", "8023", "8024", "8025"};

        //判断订单状态
        if (status.equals("0")) {
            logger.debug(String.format("订单异步回调 >> 订单异步返回:%s 成功 status: %s", serialNum, status));
            result = providerApiService.updateCallback(serialNum, voutcher, orderNo, Constant.CALL_BACK_SUCCESS);
        } else if (Arrays.asList(array).contains(status)) {
            logger.debug(String.format("订单异步回调 >> 订单异步返回:%s 失败 status: %s", serialNum, status));
            result = providerApiService.updateCallback(serialNum, "", orderNo, Constant.CALL_BACK_FAIL);
        } else {
            logger.debug(String.format("订单异步回调 >> 订单异步返回:%s 未确认 status: %s", serialNum, status));
            result = providerApiService.updateCallback(serialNum, "", orderNo, Constant.CALL_BACK_NUKNOW);
        }
        if (!result.isSuccess()) {
            result.setModel(ResultDO.FIRST_MODEL_KEY, "fail");
            return result;
        }

        result.setModel(ResultDO.FIRST_MODEL_KEY, "ok");
        return result;
    }

    @Override
    public ResultDO queryOrder(OrderStatusQueryDO domain) {
        ResultDO result = new ResultSupport();
        if (domain.getPrivateKey() == null || domain.getUserId() == null || domain.getSerialNo() == null) {
            result.setSuccess(false);
            logger.debug("查询订单 >> " + domain.getSerialNo() + " 没有查询到供货商信息配置");
            result.setModel(ResultDO.THIRD_MODEL_KEY, "没有查询到供货商信息配置");
            return result;
        }

        String requestParam = "{" +
                "\"merchantNo\":\"" + domain.getUserId() + "\"," +
                "\"serialNumber\":\"" + domain.getSerialNo() + "\"," +
                "\"timestmp\":" + System.currentTimeMillis() + "" +
                "}";

        // 发送请求
        String sendResult = HttpClientUtil.doPostJson(domain.getOrderFindUrl(), requestParam);
        switch (sendResult) {
            case "500":
                logger.debug(String.format("查询订单 >> 订单 %s -> HTTP请求失败|500", domain.getSerialNo()));
                result.setSuccess(false);
                result.setModel(ResultDO.THIRD_MODEL_KEY, "HTTP请求失败");
                return result;
            case "504":
                logger.debug(String.format("查询订单 >> 订单 %s -> HTTP请求超时|504", domain.getSerialNo()));
                result.setSuccess(false);
                result.setModel(ResultDO.THIRD_MODEL_KEY, "HTTP请求超时");
                return result;
            case "":
                logger.debug(String.format("查询订单 >> 订单 %s -> 请求没有返回信息", domain.getSerialNo()));
                result.setSuccess(false);
                result.setModel(ResultDO.THIRD_MODEL_KEY, "请求没有返回信息");
                return result;
        }
        logger.debug(String.format("查询订单 >> 订单查询返回信息: %s -> %s", domain.getSerialNo(), sendResult));

        // 解析请求返回结果转换为json对象
        JSONObject resultJson = new JSONObject();
        try {
            resultJson = JSONObject.parseObject(sendResult);
        } catch (Exception e) {
            logger.debug(String.format("查询订单 >> %s -> 请求返回结果解析JSON失败: %s", domain.getSerialNo(), sendResult));
        }
        if (resultJson.size() == 0) {
            result.setSuccess(false);
            result.setModel(ResultDO.THIRD_MODEL_KEY, "http请求失败");
            logger.debug(String.format("查询订单 >> %s -> 订单查询失败,没有返回信息", domain.getSerialNo()));
            return result;
        }

        String status = null;
        String code = null;
        String desc = "";
        try {
            code = resultJson.getString("data");
            status = resultJson.getString("status");
            if (resultJson.get("msg") != null) {
                desc = resultJson.getString("msg");
            }
        } catch (Exception e) {
            logger.debug(String.format("查询订单 >> 获取返回信息失败: %s -> %s", domain.getSerialNo(), sendResult));
        }
        if (status == null) {
            result.setSuccess(false);
            logger.debug(String.format("查询订单 >> %s -> 订单查询失败,没有返回状态码", domain.getSerialNo()));
            result.setModel(ResultDO.THIRD_MODEL_KEY, "http请求失败");
            return result;
        }


        //8001	商户号不存在
        //8002	商户验证失败
        //8003	商户秘钥重置失败
        //8004	商户资金账户错误
        //8005	非法的请求地址（绑定IP地址后，如果是非该IP地址请求）
        //8006	账户余额不足
        //8007	商品不存在
        //8017	没有该城市的充值产品
        //8019	请求太过频繁
        //8020	缺少必要参数或参数值不合法
        //8021	验证错误
        //8023	获取卡密失败
        //8024	充值号码和运营商不符合
        //8025	代理商没有关联相应的产品
        //8027	订单面值与商品金额不符合
        //8028	不是充值卡供应商
        //8029	卡密的数量和供卡数量不匹配
        //8030	服务器接收的请求已满
        //8031	商品销售亏损请设置折扣价格

        //8015	订单供应失败
        //8016	充值订单添加失败
        //8018	商品供应失败

        //500	系统异常
        //8022	订单需要手动确认
        //8026	订单不存在

        //状态码: 请求失败
        String[] requestFail = {"8001","8002","8003","8004","8005","8006","8007","8017","8019","8020","8021","8023","8024","8025","8027","8028","8029","8030","8031"};
        //状态码: 订单失败
        String[] fail = {"8015", "8016", "8018"};
        //状态码: 未确认
        String[] unKnow = {"500", "8022", "8026"};

        if (status.equals("200")) {
            switch (code) {
                case "success":
                    logger.debug(String.format("查询订单 >> 订单 %s -> 订单成功|%s", domain.getSerialNo(), desc));
                    result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.CALL_BACK_SUCCESS);
                    result.setModel(ResultDO.SECOND_MODEL_KEY, desc);
                    break;
                case "fail":
                    logger.debug(String.format("查询订单 >> 订单 %s -> 订单失败|%s", domain.getSerialNo(), desc));
                    result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.CALL_BACK_FAIL);
                    break;
                case "process":
                    logger.info(String.format("查询订单 >> 订单 %s -> 充值中|%s", domain.getSerialNo(), desc));
                    result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.CALL_BACK_PROCESS);
                    break;
                case "exception":
                    logger.debug(String.format("查询订单 >> 订单 %s -> 订单异常|%s", domain.getSerialNo(), desc));
                    result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.CALL_BACK_NUKNOW);
                    break;
                case "unconfirmed":
                    logger.debug(String.format("查询订单 >> 订单 %s -> 订单未确认|%s", domain.getSerialNo(), desc));
                    result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.CALL_BACK_NUKNOW);
                    break;
                default:
                    logger.debug(String.format("查询订单 >> 订单 %s -> 订单未知|%s", domain.getSerialNo(), desc));
                    result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.CALL_BACK_NUKNOW);
                    break;
            }
        } else if (Arrays.asList(fail).contains(status)) {
            logger.debug(String.format("查询订单 >> 订单 %s -> 订单失败|%s", domain.getSerialNo(), desc));
            result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.CALL_BACK_FAIL);
        } else if (Arrays.asList(requestFail).contains(status)) {
            result.setSuccess(false);
            logger.debug(String.format("查询订单 >> 订单 %s -> %s %s", domain.getSerialNo(), desc, status));
        } else if (Arrays.asList(unKnow).contains(status)) {
            result.setSuccess(false);
            logger.debug(String.format("查询订单 >> 订单 %s -> %s %s", domain.getSerialNo(), desc, status));
            result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.CALL_BACK_NUKNOW);
        } else {
            logger.debug(String.format("查询订单 >> 订单 %s -> %s %s", domain.getSerialNo(), desc, status));
            result.setModel(ResultDO.FIRST_MODEL_KEY, Constant.CALL_BACK_NUKNOW);
        }
        result.setModel(ResultDO.THIRD_MODEL_KEY, desc);
        return result;
    }

    @Override
    public ResultDO queryBalance(ProviderApiDO domain) {
        ResultDO result = new ResultSupport();
        if (domain.getPrivateKey() == null || domain.getUserId() == null) {
            result.setSuccess(false);
            logger.debug("余额查询 >> 没有查询到供货商信息配置");
            result.setModel(ResultDO.FIRST_MODEL_KEY, "查询失败");
            return result;
        }
//        Map<String, String> requestParamMap = new HashMap<>();
//        requestParamMap.put("merchantNo", domain.getUserId());
//        requestParamMap.put("timestmp", String.valueOf(System.currentTimeMillis()));
//        String sign = "";
//        try {
//            sign = MD5Util.md5(String.format("username=%s&key=%s", domain.getUserId(), domain.getPrivateKey()));
//        } catch (Exception e) {
//            logger.debug("余额查询 >> 签名加密失败" + e.getMessage());
//        }
        String requestParam = "{" +
                "\"merchantNo\":\"" + domain.getUserId() + "\"," +
                "\"timestmp\":" + System.currentTimeMillis() + "" +
                "}";

        // 发送请求
        String sendResult = HttpClientUtil.doPostJson(domain.getBalanceFindUrl(), requestParam);
        logger.debug(String.format("余额查询 >> 余额查询返回信息: 供应商账号 %s -> %s", domain.getUserId(), sendResult));

        // 解析请求返回结果转换为json对象
        JSONObject resultJson = new JSONObject();
        try {
            resultJson = JSONObject.parseObject(sendResult);
        } catch (Exception e) {
            logger.debug(String.format("余额查询 >> 请求返回结果解析JSON失败: %s", sendResult));
        }
        if (resultJson.size() == 0) {
            result.setSuccess(false);
            logger.debug(String.format("余额查询 >> 供应商账号: %s -> 余额查询没有返回信息", domain.getUserId()));
            result.setModel(ResultDO.FIRST_MODEL_KEY, "查询失败");
            return result;
        }

        String status = null;
        String desc = "";
        try {
            status = resultJson.getString("status");
            if (resultJson.get("msg") != null) {
                desc = resultJson.getString("msg");
            }
        } catch (Exception e) {
            logger.debug(String.format("余额查询 >> 获取返回信息失败: 供应商账号%s -> %s", domain.getUserId(), sendResult));
        }
        if (status == null) {
            result.setSuccess(false);
            logger.debug(String.format("余额查询 >> 供应商账号 %s -> 余额查询失败,没有返回状态码", domain.getUserId()));
            result.setModel(ResultDO.FIRST_MODEL_KEY, "查询失败");
            return result;
        }

        String balance = null;
        try {
            balance = resultJson.getJSONObject("data").getString("balance");
        } catch (Exception e) {
            logger.debug(e.getMessage());
        }

        if (balance == null) {
            result.setModel(ResultDO.FIRST_MODEL_KEY, desc);
            return result;
        } else {
            result.setModel(ResultDO.FIRST_MODEL_KEY, balance);
            return result;
        }

    }

    /**
     * 验证提交参数
     *
     * @param domain
     * @return boolean
     */
    private boolean verifyCommitParam(GoodsChannelDO domain) {
        // 密钥
        if (TemplateUtils.isEmpty(domain.getPrivateKey())) {
            return false;
        }
        // 流水号
        if (TemplateUtils.isEmpty(domain.getProviderSerialNumber())) {
            return false;
        }
        // 商户ID
        if (TemplateUtils.isEmpty(domain.getProviderId())) {
            return false;
        }
        // 上游账号
        if (TemplateUtils.isEmpty(domain.getUserId())) {
            return false;
        }
        // 商品编号
        if (TemplateUtils.isEmpty(domain.getProviderGoodsNo())) {
            return false;
        }
        // 面值
        if (TemplateUtils.isEmpty(domain.getAmount())) {
            return false;
        }
        // 充值号码
        if (TemplateUtils.isEmpty(domain.getRechargeNumber())) {
            return false;
        }
        // 回调地址
//        if (TemplateUtils.isEmpty(domain.getCallback())) {
//            return false;
//        }

        return true;
    }

    /**
     * <h2>提交订单返回失败</h2>
     *
     * @param success    是否处理成功
     * @param code       订单状态
     * @param logMessage 失败信息
     * @param message    供货摘要
     * @param entity     返回信息字符串
     * @return FIRST_MODEL_KEY: 订单状态
     * SECOND_MODEL_KEY: 供货摘要
     * THIRD_MODEL_KEY: 上游返回信息字符串
     */
    private ResultDO returnFail(boolean success, int code, String logMessage, String message, String entity) {
        ResultDO result = new ResultSupport();
        result.setSuccess(success);
        result.setModel(ResultDO.FIRST_MODEL_KEY, code);
        result.setModel(ResultDO.SECOND_MODEL_KEY, message);
        result.setModel(ResultDO.THIRD_MODEL_KEY, entity);
        logger.debug(logMessage);
        return result;
    }

}

